這張圖是 Hello world 執行後,歷經的過程。
Reference
這裡要先辨別,作業系統的 User space 與 Kernel space 的差異。Kernel space 可以操作任何的系統資源,包括存取任何位置的記憶體,相對的,User space 能存取的資源相對有限。這樣分開的目的也很簡單,避免當 User Space 故障的時候,整個系統連帶崩潰。舉例來說,在 User Space 執行程式,就好比你在使用的 Chrome 瀏覽器,當它遭受某種原因而無法執行,你總不希望你的 Youtube 正在播放音樂受到影響吧?因此,區別 User space 與 kernel space 可以有效的讓重要的程式不受使用者的影響。
首先,先找到昨天寫的 Helloworld 程式,準備執行它
接著在 terminal 中,下指令:
strace ./helloworld
得到結果如下:
execve("./helloworld", ["./helloworld"], 0x7ffea93b1be0 /* 35 vars */) = 0
brk(NULL) = 0x555598cec000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd42478d60) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=78465, ...}) = 0
mmap(NULL, 78465, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb5ede6e000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360r\2\0\0\0\0\0"..., 832) = 832
lseek(3, 64, SEEK_SET) = 64
read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784
lseek(3, 848, SEEK_SET) = 848
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
lseek(3, 880, SEEK_SET) = 880
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\313\351\317\363\304;\227\2279\257\26\201\266\32=X"..., 68) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2025032, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb5ede6c000
lseek(3, 64, SEEK_SET) = 64
read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784
lseek(3, 848, SEEK_SET) = 848
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
lseek(3, 880, SEEK_SET) = 880
read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\313\351\317\363\304;\227\2279\257\26\201\266\32=X"..., 68) = 68
mmap(NULL, 2032984, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb5edc7b000
mmap(0x7fb5edca0000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7fb5edca0000
mmap(0x7fb5ede18000, 303104, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0x7fb5ede18000
mmap(0x7fb5ede62000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e6000) = 0x7fb5ede62000
mmap(0x7fb5ede68000, 13656, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb5ede68000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7fb5ede6d540) = 0
mprotect(0x7fb5ede62000, 12288, PROT_READ) = 0
mprotect(0x5555984e6000, 4096, PROT_READ) = 0
mprotect(0x7fb5edeae000, 4096, PROT_READ) = 0
munmap(0x7fb5ede6e000, 78465) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
brk(NULL) = 0x555598cec000
brk(0x555598d0d000) = 0x555598d0d000
write(1, "Hello, world!\n", 14Hello, world!
) = 14
exit_group(14) = ?
+++ exited with 14 +++
在 Hello world 被呼叫後,經過以上過程。因為 strace 從 fork() 後開始追,因此,第一個獲得的函式是execve(),後續步驟包含寫入、寫出資料、最後離開。
在 terminal 中,下指令:
ltrace ./helloworld
得到結果如下:
Hello, world!
+++ exited (status 14) +++
輸出無結果
這兩天的文章是程式的ㄧ生與它執行後的結果。明天開始就會開始帶一些實戰,讓大家好好瞭解特定程式碼的長相!